/* <pre>
 * Copyright (c) The Loose Coupling Team.
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 *
 *      http://www.apache.org/licenses/LICENSE-2.0 
 *
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 *</pre>
 */
package org.lc.eic.synchronizer.request.impl;

import java.sql.Timestamp;

import org.apache.log4j.Logger;
import org.lc.eic.synchronizer.request.exception.RequestCanceledException;
import org.lc.eic.synchronizer.request.exception.RequestTimeoutException;



/**
 *  Encapsulates an ongoing-request
 *	@author <a href="mailto:p.lycke@googlemail.com">PaLy</a>
 *
 * 
 */
public class OngoingRequest<I, O>  {
	private static final  Logger logger = Logger.getLogger(OngoingRequest.class);
	
	private String correlationID;
	private String uniqueID;
	private Timestamp expirationTime;
	private I request;
	private O reply;
	
	
	
	private boolean canceled = false;
	private String canceledReason = "-";
	private Throwable cancelThrowable = null;
	
	private boolean responseArrived = false;
	
	public String getCorrelationID() {
		return correlationID;
	}
	public void setCorrelationID(String correlationID) {
		this.correlationID = correlationID;
	}
	public Timestamp getExpirationTime() {
		return expirationTime;
	}
	public void setExpirationTime(Timestamp expirationTime) {
		this.expirationTime = expirationTime;
	}
	public I getRequest() {
		return request;
	}
	public void setRequest(I request) {
		this.request = request;
	}
	
	
	public void waitForResponse() throws RequestTimeoutException, RequestCanceledException {
		synchronized(this){		
			
			while(!responseArrived){
				long timeLeft = expirationTime.getTime()- System.currentTimeMillis(); 
				
				if(logger.isDebugEnabled()){
					logger.debug("Time-left: "+timeLeft+" ms");
				}
				
				
				if(!responseArrived){					
					if(timeLeft <= 0){
						throw new RequestTimeoutException("Request has timed-out");
					}
				}
				
				if(canceled){
					if(cancelThrowable != null){
						throw new RequestCanceledException("Request has been canceled. [canceledReason="+canceledReason+"]", cancelThrowable);
					} else{
						throw new RequestCanceledException("Request has been canceled. [canceledReason="+canceledReason+"]");
					}
				}
				
				try {
				
					wait(timeLeft);
					
					
				} catch (InterruptedException e) {
					throw new RequestTimeoutException("Request thread has been interrupted.", e);
				}
			}
			
			if(logger.isDebugEnabled()){
				logger.debug("Reply has arrived!");
			}
		}
		
		
		
	}
	
	
	
	public void cancelRequest(String reason){
		cancelRequest(reason, null);
	}
	
	public void cancelRequest(String reason, Throwable throwable){
		synchronized(this){
			canceled = true;
			cancelThrowable = throwable;
			notifyAll();
		}
	}
	
	public void setReply(O response) {
		synchronized(this){
			responseArrived = true;
			this.reply = response;
			notifyAll();
		}
	}
	public O getReply() {
		return reply;
	}
	public String getUniqueID() {
		return uniqueID;
	}
	public void setUniqueID(String uniqueID) {
		this.uniqueID = uniqueID;
	}
	
	

}
